//
//  BLETransDeviceSingleton.m
//  AppsControl
//
//  Created by Kent Ng on 15/6/5.
//  Copyright (c) 2015年 justin yang. All rights reserved.
//

#import "BLETransDeviceSingleton.h"
#import "DataModal.h"
#import "LXDevSettingModel.h"

static const NSInteger AutoSynchronousDataIndex = 8;
static const int forwardBit = 8;
static const int idem = 0xFF;

NSString *const unitHeadName = @"CE262A";
const NSInteger AutoSynchronousData[AutoSynchronousDataIndex] = {
    
};

@implementation BLETransDeviceSingleton
{
    NSInteger currcntLen;
    NSInteger totleLen;
    NSInteger autoSynchronousCurrent;
    NSInteger RepeatSychronounsCurrent;
    AppDelegate *delegate;
    BOOL syhOkOrFail;
    BOOL longData;
    BOOL scanSuccess;
    NSArray *UUID_ARRAY;
}

@synthesize centralManager;
@synthesize discoveredPeripheral;
@synthesize cbCharacteristcs;
@synthesize _Peripheral;

@synthesize BleConnected;

static BLETransDeviceSingleton *sharedSingleton_ = nil;

- (void) operation
{
    // do something
    NSLog(@"Singleton");
    centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    _mutableData = [[NSMutableData alloc] init];
    _window = [[UIApplication sharedApplication].delegate window];
    _peripheralsArray = [[NSMutableArray alloc] init];
    _Characteristics = [[NSMutableArray alloc] init];
    UUID_ARRAY = @[DEV_CHARACTERISTIC_UUID, TEM_CHARACTERISTIC_UUID, NOT_CHARACTERISTIC_UUID];
    
    delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
}

+ (BLETransDeviceSingleton *)sharedInstance
{
    static BLETransDeviceSingleton *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[BLETransDeviceSingleton alloc] init];
    });
    return instance;
}

-(void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    //    NSLog(@"centralManagerDidUpdateState %ld",(long)central.state);
    switch (central.state) {
        case CBCentralManagerStatePoweredOff://蓝牙未打开，系统会自动提示打开，所以不用自行提示
            BleConnected = NO;
            [EasyTextView showInfoText:NSLocalizedString(@"BluetoothNotOpened", nil)];
            if (_delegate && [_delegate respondsToSelector:@selector(BLETransDeviceSingletonBlueTooch:)]) {
                [_delegate BLETransDeviceSingletonBlueTooch:NO];
            }
            break;
        case CBCentralManagerStatePoweredOn:
            NSLog(@"蓝牙已打开,请扫描外设");
            if (_delegate && [_delegate respondsToSelector:@selector(BLETransDeviceSingletonBlueTooch:)]) {
                [_delegate BLETransDeviceSingletonBlueTooch:YES];
            }
            [self scan];
            break;
        case CBCentralManagerStateUnauthorized:
            NSLog(@"未授权");
            [EasyTextView showInfoText:NSLocalizedString(@"Unauthorized", nil)];
        case CBCentralManagerStateUnsupported:
            NSLog(@"您的设备不支持蓝牙或蓝牙4.0");
            [EasyTextView showErrorText:NSLocalizedString(@"BluetoothNotSupported", nil)];
            if (_delegate && [_delegate respondsToSelector:@selector(BLETransDeviceSingletonBlueTooch:)]) {
                [_delegate BLETransDeviceSingletonBlueTooch:NO];
            }
            break;
            
        case CBManagerStateUnknown:
            
            break;
        case CBManagerStateResetting:
            
            break;
    }
}

-(void)scan
{
//    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE_UUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES }];
    [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@NO}];
    
    //30秒以后停止
    double delayInSeconds = 5.0;
    [EasyLoadingView showLoading];
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [self stop];//停止扫描
        NSLog(@"Stop Scanning");
    });
}

-(void)stop {
    [self.centralManager stopScan];
    NSLog(@"Scanning stoped");
    [EasyLoadingView hidenLoading];
    if (!scanSuccess) {
        [EasyTextView showInfoText:NSLocalizedString(@"NotFoundPeripheral", nil)];
    } else {
        
    }
}

//已发现从机设备
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    NSLog(@"Discovered %@ at %@ at %ld", peripheral.name, RSSI,(long)central.state);
    NSString *peripheraName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
    NSLog(@"peripheraName %@", peripheraName);
    // Ok, it's in range - have we already seen it?
    if ([peripheraName isEqualToString:@"Step"]) {
        scanSuccess = YES;
        [self stop];
        self.discoveredPeripheral = peripheral;
        [self connect:peripheral];
    } else {

    }
}

//连接设备
-(BOOL)connect:(CBPeripheral *)peripheral{
    NSLog(@"connect start");
    [self.centralManager connectPeripheral:peripheral options:nil];
    //[self.centralManager connectPeripheral:peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
    
    //开一个定时器监控连接超时的情况
    _connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(connectTimeout:) userInfo:peripheral repeats:NO];
    [EasyLoadingView showLoadingText:NSLocalizedString(@"Connecting", nil)];
    return YES;
}

- (BOOL)disConnect
{
    if (_Peripheral && ![_Peripheral.name isEqualToString:@""]) {
        [self.centralManager cancelPeripheralConnection:_Peripheral];
    }
    return YES;
}

- (void)reConnect
{
    [self connect:_Peripheral];
}

/** If the connection fails for whatever reason, we need to deal with it.
 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
    [self cleanup];
    [EasyLoadingView hidenLoading];
    [_connectTimer invalidate];
    [EasyTextView showErrorText:NSLocalizedString(@"ConncetFailed", nil)];
    if (_delegate && [_delegate respondsToSelector:@selector(BLETransDeviceSingletonConnected:)]) {
        [_delegate BLETransDeviceSingletonConnected:NO];
    }
}

- (void)connectTimeout:(CBPeripheral *)peripheral
{
    NSLog(@"Out Time");
    [self.centralManager stopScan];
    [_connectTimer invalidate];
    [EasyLoadingView hidenLoading];
    [EasyTextView showInfoText:NSLocalizedString(@"ConncetOutTime", nil)];
}

/** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic.
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@"Peripheral Connected");
    [UIApplication sharedApplication].idleTimerDisabled = YES;
    BleConnected = YES;
    // Stop scanning
    [_connectTimer invalidate];
    [EasyLoadingView hidenLoading];
    [EasyTextView showSuccessText:NSLocalizedString(@"ConnectSuccess", nil)];
    NSLog(@"Scanning stopped");
    peripheral.delegate = self;

    [peripheral discoverServices:nil];//发现服务
    // Search only for services that match our UUID
    //[peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
    if (_delegate && [_delegate respondsToSelector:@selector(BLETransDeviceSingletonConnected:)]) {
        [_delegate BLETransDeviceSingletonConnected:YES];
    }
}

/** Once the disconnection happens, we need to clean up our local copy of the peripheral
 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"Peripheral Disconnected");
    //    UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"lost connect.png" ofType:nil]];
    [EasyTextView showErrorText:@"The blueTooth is disconected"];
    [UIApplication sharedApplication].idleTimerDisabled = NO;
    BleConnected = NO;
    if (_delegate && [_delegate respondsToSelector:@selector(BLETransDeviceSingletonDisConnected:)]) {
        [_delegate BLETransDeviceSingletonDisConnected:YES];
    }
}


/** Call this when things either go wrong, or you're done with the connection.
 *  This cancels any subscriptions if there are any, or straight disconnects if not.
 *  (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
 */
- (void)cleanup
{
    [self.peripheralsArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        CBPeripheral *cb = obj;
        if (cb.services != nil) {
            for (CBService *service in cb.services) {
                if (service.characteristics != nil) {
                    for (CBCharacteristic *characteristic in service.characteristics) {
                        if (characteristic.isNotifying) {
                            [cb setNotifyValue:NO forCharacteristic:characteristic];
                            return;
                        }
                    }
                }
            }
        }
        [self.centralManager cancelPeripheralConnection:cb];
    }];
    // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
    
}

/** The Transfer Service was discovered
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    if (error) {
        NSLog(@"Error discovering services: %@", [error localizedDescription]);
        [self cleanup];
        return;
    }
    
    for (CBService *s in peripheral.services){
        NSLog(@"服务 UUID:%@(%@)",s.UUID.data, s.UUID);
        [peripheral discoverCharacteristics:nil forService:s];
    }
    
    // Loop through the newly filled peripheral.services array, just in case there's more than one.
    for (CBService *service in peripheral.services) {
        [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:SERVICE_UUID]] forService:service];
    }
}

/** The Transfer characteristic was discovered.
 *  Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    // Deal with errors (if any)
    if (error) {
        NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
        [self cleanup];
        return;
    }
    
    for (CBCharacteristic *c in service.characteristics) {
        NSLog(@"特征UUID:%@(%@)",c.UUID.data, c.UUID);
        [_Characteristics addObject:c];
    }
    // Again, we loop through the array, just in case.
    for (CBCharacteristic *characteristic in service.characteristics) {
        if ([characteristic.UUID.UUIDString isEqualToString:@"FFF2"] || [characteristic.UUID.UUIDString isEqualToString:@"FFF3"]) {
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
        if ([characteristic.UUID.UUIDString isEqualToString:@"FFF3"]) {
            [self secretKeySendTimeAlert:0 boundsAlert:0 alertOn:NO];
        }
    }
    _Peripheral = peripheral;
    [self saveObject:_Peripheral.name forKey:BLUENAME];
}

/** This callback lets us know more data has arrived via notification on the characteristic
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error) {
        NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
        return;
    }
    NSData *returnData = [[NSData alloc] initWithData:characteristic.value];
    NSLog(@"==========Received:%@", returnData);
    NSUInteger len = returnData.length;
    if(len > 0){
        NSLog(@">>>>>>>>>>>:%@", returnData);
        [self headUnitNotificationCenter:characteristic.UUID.UUIDString whitData:returnData lenght:totleLen];
        totleLen = 0;
        [_mutableData resetBytesInRange:NSMakeRange(0, [_mutableData length])];//清空数据
        [_mutableData setLength:0];                                           //重设长度
    } else {
        NSLog(@"head unit data error %@",returnData);
    }
}

- (NSInteger)highOrder:(Byte)hight lowOrder:(Byte)low {
    NSInteger cmd = 0;
    cmd <<= 8;
    cmd |= hight & 0xff;
    cmd <<= 8;
    cmd |= low & 0xff;
    return cmd;
}

- (void)headUnitNotificationCenter:uuidString whitData:(NSData *)data lenght:(NSInteger)len
{
    //NSMutableData *data = [self DataChange:cmd lenght:len];
    NSDictionary *objects = @{kAppHeadUnitData:data};
    [UUID_ARRAY enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString *uuid = obj;
        if ([uuid rangeOfString:uuidString].location != NSNotFound) {
            [[NSNotificationCenter defaultCenter] postNotificationName:uuid object:self userInfo:objects];
        }
    }];
}

/** The peripheral letting us know whether our subscribe/unsubscribe happened or not
 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error) {
        NSLog(@"Error changing notification state: %@", error.localizedDescription);
    }
    
    // Exit if it's not the transfer characteristic
    if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:DEV_CHARACTERISTIC_UUID]]) {
        return;
    }
    
    // Notification has started
    if (characteristic.isNotifying) {
        cbCharacteristcs = characteristic;
        autoSynchronousCurrent = 0;
        syhOkOrFail = YES;
    } else {
        // so disconnect from the peripheral
        NSLog(@"Notification stopped on %@.  Disconnecting", characteristic);
        [self.centralManager cancelPeripheralConnection:peripheral];
    }
}

- (NSInteger)CmdHead:(Byte)frist second:(Byte)second
{
    return (frist << forwardBit) + second;
}

- (void)AppGiveHUAck:(NSInteger) ackHead
{
//    Byte ack[4] = {(AppAck >> forwardBit) & idem,AppAck & idem,(ackHead >> forwardBit) & idem,ackHead & idem};
//    [self writeData:ack length:sizeof(ack)];
}

- (void)characteristc:(NSString *)uuid sendHostCmd:(Byte *)data lenght:(NSInteger)len;
{
    __block CBCharacteristic *currentCB;
    [_Characteristics enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        CBCharacteristic *cb = obj;
        if ([uuid rangeOfString:cb.UUID.UUIDString].location != NSNotFound) {
            currentCB = cb;
        }
    }];
    if (!currentCB) {
        return;
    }
    [self characteristc:currentCB writeData:data length:len];
}

- (void)characteristc:(CBCharacteristic *)characteristic writeData:(Byte *)CmdData length:(NSInteger)len
{
    if ((len <= 512) && (BleConnected == YES)) {
        UInt8 dataBuf[len];
        for (int i = 0; i < len; i ++) {
            dataBuf[i] = CmdData[i];
        }
        NSData *myData = [NSData dataWithBytes:dataBuf length:len];
        NSLog(@"send host short data:%@", myData);
        [_Peripheral writeValue:myData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }
}

- (void)secretKeySendTimeAlert:(NSInteger)timeAlert boundsAlert:(NSInteger)boundsAlert alertOn:(BOOL)on {
    UInt8 data[13];
    data[0] = 0x44;
    data[1] = 0x66;
    data[2] = 0x00;
    data[3] = 0x77;
    data[4] = 0x44;
    data[5] = 0x11;
    data[6] = 0x11;
    data[7] = 0x22;
    data[8] = 0x44;
    data[9] = [LXDevSettingModel shareSettingModel].tempUnitF ? 0x01 : 0x00;
    data[10] = on ? 0x01 << boundsAlert : 0x00 << boundsAlert;
    data[11] = timeAlert & 0xff;
    data[12] = on ? 0x00 : 0x01;
    [[BLETransDeviceSingleton sharedInstance] characteristc:DEV_CHARACTERISTIC_UUID sendHostCmd:data lenght:13];
}
@end
